package buffer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * FIFO queue
 * 
 * @author grim
 *
 * @param <T>
 */
public class FIFO<T> implements Buffer<T> {
	
	private static Log log = LogFactory.getLog(FIFO.class.getName());
	
	public static final int DEFAULT_SIZE = 10;
	private Vector<T> items;
	
	/*
	 * start >= end			[.....e######s.....]
	 * start < end			[#####s......e#####]
	 */
	private int start;
	private int size;
	private int capacity;
	
	public FIFO() {
		this(DEFAULT_SIZE);
	}
	
	public FIFO(int initialCapacity) {
		start = size = 0;
		items = new Vector<T>(capacity = initialCapacity);
		for (int i = 0; i < capacity; i++) items.add(null);
	}
	
	/* (non-Javadoc)
	 * @see buffer.Buffer#put(T)
	 */
	public void put(T data) {
		items.set((start + size++) % capacity, data);
		
		log.debug("put: " + data);
		dump();
	}
	
	/* (non-Javadoc)
	 * @see buffer.Buffer#get()
	 */
	public T get() {
		T item = items.get(start);
		size--;
		start = (start + 1) % capacity;
		
		log.debug("get: " + item);		
		dump();
		return item; 
	}

	public void dump() {
		log.debug("  start: " + start);
		log.debug("  size: " + size);
		log.debug("  capacity: " + capacity);
		log.debug("  dump[ ");
		for (int i = 0; i < size; i++) {
			log.debug("     " + (start + i) % capacity + ": " + items.get((start + i) % capacity));
		}
		log.debug("  ]");
	}
	
	public int size() {
		return size;
	}
	
	public int capacity() {
		return capacity;
	}
	
	
	@Override
	public boolean isEmpty() {
		return (size() <= 0);
	}

	@Override
	public boolean isFull() {
		return (size() >= capacity());
	}

	public Iterator<T> iterator() {
		return new FIFOIterator<T>(this);
	}

	private class FIFOIterator<Y> implements Iterator<Y> {

		private FIFO<Y> fifo;
		
		
		public FIFOIterator(FIFO<Y> fifo) {
			this.fifo = fifo;
		}

		@Override
		public boolean hasNext() {
			return fifo.size() > 0;
		}

		@Override
		public Y next() {
			return fifo.get();
		}

		@Override
		public void remove() {
			
		}
		
	};
}
